﻿using AiMoWindows.Localization;
using System.Drawing;
using System.IO;
using System.Text;

namespace AiMoWindows.CodeScripts.IO
{
    static class CodeIOUtils
    {
        const string SpliterMajor = "^6A8D6C05F2C8^";
        const string SpliterMinor = "^0D19E3E66614^";
        const double IOVersion = 0.5;

        public static byte[] GetBytes(Dictionary<string, string> pairs, Bitmap? bitmap)
        {
            StringBuilder builder = new StringBuilder();
            AddToBuilder(builder, "IOVersion", IOVersion.ToString());

            foreach (KeyValuePair<string, string> pair in pairs)
            {
                AddToBuilder(builder, pair.Key, pair.Value);
            }
            byte[] contentBytes = Encoding.UTF8.GetBytes(builder.ToString());
            byte[] imgBytes = Array.Empty<byte>();
            if (bitmap != null)
            {
                MemoryStream stream = new MemoryStream();
                bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                imgBytes = stream.GetBuffer();
                stream.Close();
                stream.Dispose();
            }
            byte[] bytes = new byte[contentBytes.Length + imgBytes.Length + 8];

            Array.Copy(BitConverter.GetBytes(contentBytes.Length), 0, bytes, 0, 4);
            if (imgBytes != null)
                Array.Copy(BitConverter.GetBytes(imgBytes.Length), 0, bytes, 4, 4);
            else
                Array.Copy(BitConverter.GetBytes(0), 0, bytes, 4, 4);
            Array.Copy(contentBytes, 0, bytes, 8, contentBytes.Length);
            if (imgBytes != null)
                Array.Copy(imgBytes, 0, bytes, 8 + contentBytes.Length, imgBytes.Length);

            return bytes;
        }

        public static bool FromBytes(byte[] bytes, Dictionary<string, string> pairs, out Bitmap? bitmap, out string error)
        {
            error = "";
            bitmap = null;

            if (bytes.Length < 8)
            {
                error = "bytes length is not enough";
                return false;
            }
            int contentLength = BitConverter.ToInt32(bytes, 0);
            int imgLength = BitConverter.ToInt32(bytes, 4);
            if (bytes.Length != contentLength + imgLength + 8)
            {
                error = "bytes length verify error";
                return false;
            }
            string content = Encoding.UTF8.GetString(bytes, 8, contentLength);
            foreach (string major in content.Split(new string[] { SpliterMajor }, StringSplitOptions.RemoveEmptyEntries))
            {
                string[] kvp = major.Split(new string[] { SpliterMinor }, StringSplitOptions.RemoveEmptyEntries);
                if (kvp.Length > 1)
                {
                    string key = kvp[0].Trim();
                    string value = kvp[1];
                    if (key == "IOVersion")
                    {
                        if (double.TryParse(value, out double result))
                        {
                            if (result > IOVersion)
                            {
                                error = Local.Get("AiMoScript version is not compatible with current AiMo. Please update to the latested version. ") + Server.ServerHelper.CommunityAddress;
                                return false;
                            }
                        }
                        else
                        {
                            error = "Cannot get valid code IOVersion";
                            return false;
                        }
                    }
                    else
                    {
                        pairs[key] = value;
                    }
                }
            }
            if (imgLength > 0)
            {
                try
                {
                    MemoryStream stream = new MemoryStream();
                    stream.Write(bytes, 8 + contentLength, imgLength);
                    bitmap = new Bitmap(Image.FromStream(stream));

                    stream.Close();
                    stream.Dispose();
                    return true;
                }
                catch (Exception ex)
                {
                    error = "Cannot decode screenshot" + ex.Message;
                    return false;
                }
            }

            return true;
        }

        public static void AddToBuilder(StringBuilder stringBuilder, string key, string value)
        {
            if (!string.IsNullOrEmpty(value)) stringBuilder.Append(SpliterMajor + key + SpliterMinor + value);
        }

    }
}
